Typing of expressions

Neuron Power Engineer →types →expressions and →assignments according to the following rules:

  • The data type of the →variable to store the result of the →overloaded function influences the data type of the result of the function or operation. This rule does not correspond to the specifications within the →IEC-standard.

    Examples
    VAR
      int1, int2, int3 : INT := 32767;
      dint1 : DINT := 32767;
      ResultInt1 : INT;
      ResultDint1, ResultDint2 : DINT;  
    END_VAR
     
    ResultInt1  := int1 + int2;    (* The addition is performed as an INT-operation. *)
    ResultDint1 := int1 + int2;    (* In contrast to the IEC-standard: 'int1' and 'int2' are converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDint1'. *)
    ResultDint2 := dint1 + int3;   (* 'int3' is converted to DINT. The addition is performed as a DINT addition. *)
  • If the expressions do not include any concrete data type, typing is influenced by the data type of the variable to store the result of the overloaded function. This addon rule is an implementer-specific realization because the IEC-standard does not specify any on this.

    Examples
    VAR
      ResultDintA, ResultDintB, ResultDintC : DINT;
      sint1 : SINT := 127;
    END_VAR     
     
    ResultDintA := 127 + 127;       (* The addition is performed as an DINT-operation because there is no other concrete data type. *)
    ResultDintB := 127 + SINT#127;  (* 'SINT#127' is converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDintB'. *)
    ResultDintC := 127 + sint1;     (* 'sint1' is converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDintC'.*)
  • In case of a →call that is using inputs, outputs and/or a return value with the same →generic data typeNeuron Power Engineer types all of these inputs, outputs and the return value of the call – even if only one of these elements is connected to a concrete data type.

    Examples
    VAR
      Var1, OUT1 : INT;
      iForceMrk1 : FORCEMRK;
    END_VAR
     
    Var1 := ADD(IN1 := 1, IN2 := 3);
    (* The inputs and the return value of 'ADD' are using the same generic data type. As the INT variable 'Var1' is assigned to the call of 'ADD' (in particular to the return value of 'ADD'), the call is typed with 'INT'. Subsequently, the inputs of 'ADD' are typed with 'INT' as well. *)
     
    iForceMrk1(IN := 3, OUT => OUT1);
    (* The input and the output of 'FORCEMRK' are using the same generic data type. As output 'OUT' of 'iForceMrk1' is assigned to the INT variable 'OUT1', the call is typed with 'INT'. Subsequently, the input of 'iForceMrk1' is typed with 'INT' as well. *)

    If a →user-defined data type is used for typing, Neuron Power Engineer uses the →base type. This rule is of importance, if an →Initial value is defined within the user-defined data type – in this case the initial value of the data type is not used but the initial value of the base type.
    Compare: In case of an →array data type (incl. an ARRAY declaration of a variable) or a →structured data type, the user-defined data type is the base type.

    Examples
    TYPE
      MyInt : INT := 6;
      MyStruct : Struct
        Elem1 : MyInt;
      END_STRUCT;
      MyArray : Array [1..1] OF MyInt := [99];
    END_TYPE
     
    FUNCTION_BLOCK myFB
      VAR
        outDerived : MyInt;
        outArray1 : MyArray;
        outArray2 : Array [1..1] OF MyInt;
        outStruct : MyStruct;    
        iForceMrk1, iForceMrk2, iForceMrk3, iForceMrk4 : FORCEMRK;
      END_VAR
     
      iForceMrk1(OUT => outDerived);
      (* 'OUT' gets value '0' because initial value '0' of 'INT' is used. Here the base type is 'INT'. *)
      (* The initial value '6' of 'MyInt' is NOT used. *)
      
      iForceMrk2(OUT => outArray1);
      iForceMrk3(OUT => outArray2);
      iForceMrk4(OUT => outStruct);
      (* Each element of output 'OUT' gets value '6' because initial value '6' of 'MyINT' is used. *)
      (* Here the base type of each element is 'MyInt* while the base type of 'OUT' is 'ARRAY [...] OF' or 'STRUCT'. *)
      
    END_FUNCTION_BLOCK
  • In 2 or more calls are connected with each other and their connected inputs, outputs and/or the connected return value are of a generic data type (but the others are of a concrete data type), Neuron Power Engineer types all of these inputs, outputs and the return value of the call by using the lowest common data type.
    Example: The return value of the PACK block is of the generic data type ANY_ELEMENTARY and the inputs are of the concrete data type BYTE, the input of the TO_DINT block is also of the generic data type ANY_ELEMENTARY and the return value is of the concrete data type DINT.
    For versions before 3.25.0 and in case of the following code, the return value of PACK and the input of TO_DINT have been typed with BOOL (BOOL is the lowest common data type of ANY_ALEMENTARY).
    For the version 3.25.0 and later, the code is highlighted as faulty because it is not allowed to connect the return value of PACK to a block input of a generic data type in these versions.

    Example
    VAR
      Var1 : DINT;
      ByteVar1 : BYTE:= 16#AB;
    END_VAR
     
    Var1 := TO_DINT(PACK(ByteVar1, ByteVar1)); (* This line is highlighted as faulty in V3.25.0 and later. *)

    Do not nest the calls in order to avoid the typing using to the lowest common data type or the reported error for PACK.
    Workaround 1: Declare an auxiliary variable. Assign one call to this auxiliary variable. Assign this auxiliary variable as parameter for the other call.

    Example for workaround 1

    VAR
      Var1 : DINT;
      ByteVar1 : BYTE := 16#AB;
      HelperVar : DINT;                        (* the auxiliary variable *) 
    END_VAR
     
    HelperVar := PACK(ByteVar1, ByteVar1);
    Var1 := TO_DINT(HelperVar);                (* 'Var1' evaluates to value '43947'. This a value as expected from 'PACK' *)

    Workaround 2: Create a user-defined POU (e.g. a function). Assign one call of the blocks (in the following example: PACK) to the result value of the function. Call the function as parameter of the other block (then: DINT).

    Example for workaround 2
    FUNCTION myFun1 : DWORD
      VAR
        ByteVar1 : BYTE:= 16#AB;
      END_VAR
     
      myFun1 := PACK(ByteVar1, ByteVar1);     (* 'PACK' is assigned to the return value of function 'myFun1'. *)
    END_FUNCTION
     
    FUNCTION_BLOCK myFB2
      VAR
        Var1 : DINT;
      END_VAR
      
      Var1 := TO_DINT(IN:=myFun1());           (* 'Var1' evaluates to value '43947'. This a value as expected from 'PACK'. *)
    END_FUNCTION_BLOCK